/*
 * Copyright 2003-2007 (c) Live Media Pty Ltd. <argot@einet.com.au> 
 *
 * This software is licensed under the Argot Public License 
 * which may be found in the file LICENSE distributed 
 * with this software.
 *
 * More information about this license can be found at
 * http://www.einet.com.au/License
 * 
 * The Developer of this software is Live Media Pty Ltd,
 * PO Box 4591, Melbourne 3001, Australia.  The license is subject 
 * to the law of Victoria, Australia, and subject to exclusive 
 * jurisdiction of the Victorian courts.
 */

package com.colony.networkvm.proxy;

import java.io.IOException;

import com.argot.TypeException;
import com.argot.TypeInputStream;
import com.argot.TypeOutputStream;
import com.argot.TypeReader;
import com.argot.TypeWriter;
import com.argot.common.BigEndianUnsignedShort;
import com.argot.remote.MetaMethod;
import com.argot.remote.MetaParameter;
import com.colony.networkvm.NvmProxyDelegate;
import com.colony.networkvm.instruction.NvmInstruction;
import com.colony.networkvm.machine.NvmInstance;
import com.colony.remote.RemoteException;

public class NvmMetaMethodCall 
implements NvmInstruction
{
    public NvmMetaMethodCall()
    {
        // dummy for TypeWriter.
    }

    public static final String TYPENAME = "nvm.instruction.meta_method_call";
	
	private int _methodId;

	
	public NvmMetaMethodCall( int methodId )
	{
		this._methodId = methodId;
	}

    public void execute(NvmInstance request) 
    throws RemoteException
    {
    	request.incProgramCounter();
        try
        {
        	// The object to call is on the stack.
            Object obj = request.pop();
            
            // find the method we want to call.
            MetaMethod mMethod = (MetaMethod) request.getTypeLibrary().getStructure( _methodId );
            
            MetaParameter[] requestTypes = mMethod.getRequestTypes();
            
            // pop arguments off the stack.            
            Object[] args = new Object[ requestTypes.length ];
            for (int x=0; x< requestTypes.length; x++ )
            {
            	// would be nice to check requestType ids to stack ids.
            	// problem is that we may have abstract/concrete type mistmatches.
            	
            	args[x] = request.pop();
            }
            
            
            // prepare the call.
            NvmMetaMethodRequest methodRequest = new NvmMetaMethodRequest( mMethod, args );
            
    		NvmProxyDelegate back = request.getEnvironment().getBackDelegate( obj.getClass() );
    		if ( back == null )
    		{
    			throw new RemoteException( "no server delegate to invoke method" );
    		}
            back.processProxy( methodRequest, obj );
            
            Throwable e = methodRequest.getException();
            if ( e != null )
            {
            	request.setException(e);
            }
            else
            {
            	Object r = methodRequest.getReturnValue();
            	request.push(  r );
            }
        }
        catch (TypeException e)
        {  
            e.printStackTrace();
            request.setException(e);
        } 
        catch (RemoteException e)
        {
            e.printStackTrace();
            request.setException(e);
        }
 		
    }

    public static class NvmMetaMethodCallTypeWriter
    implements TypeWriter
    {
	    public void write(TypeOutputStream out, Object o) throws TypeException, IOException
	    {
	       NvmMetaMethodCall call = (NvmMetaMethodCall)o;
	       int id = call._methodId;
	       out.writeObject( BigEndianUnsignedShort.TYPENAME, new Integer( id ));
	    }
    }

    public static class NvmMetaMethodCallTypeReader
    implements TypeReader
    {
	    public Object read(TypeInputStream in) throws TypeException, IOException
	    {
	        Integer methodId = (Integer) in.readObject(BigEndianUnsignedShort.TYPENAME );
	        return new NvmMetaMethodCall( methodId.intValue() );
	    }
    }

}
